//
// Created on 2023/12/18.
//
// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found,
// please include "napi/native_api.h".

#ifndef MyNapi_threadsafe_manager_H
#define MyNapi_threadsafe_manager_H

#include <unordered_map>
#include <string>
#include <mutex>
#include <condition_variable>
#include "napi/native_api.h"

using namespace std;
namespace threadsafe {
/*
 * 用户自定义结构体，用来存储必要信息.
 * */
struct TSInfo {
    napi_threadsafe_function_call_mode blockOnFull = napi_tsfn_blocking;
    uint32_t maxQueueSize = 0;
    napi_threadsafe_function_call_js jsCallBack = nullptr;
    napi_finalize jsFinalizeCallBack = nullptr;
    void *finalizeData = nullptr;
    string name = "";
    TSInfo(string name, napi_threadsafe_function_call_js callJS, napi_finalize cb, void *data = nullptr);
};

struct ResultInfo {
    void *data = nullptr;
};

class ThreadSafeManager {
public:
    static ThreadSafeManager &GetThreadSafeManager();
    static void Print();

    bool CreateThreadSafeFunction(napi_env env, napi_value cb, TSInfo *tsInfo);
    bool Call(string funcName, void *data, napi_threadsafe_function_call_mode isBlocking);
    void RemoveThreadSafeFunction(string name, napi_threadsafe_function_release_mode mode = napi_tsfn_abort);
    void SetDataOfContext(string funcName, void *data) {
        unique_lock<mutex> lock(functionsLock_);
        auto iter = functions_.find(funcName);
        if (iter == functions_.end()) {
            return;
        }
        auto fn = iter->second;
        void *hint = nullptr;
        napi_get_threadsafe_function_context(fn, &hint);
        TSInfo *info = static_cast<TSInfo *>(hint);
        info->finalizeData = data;
    }
    ~ThreadSafeManager() {
        unique_lock<mutex> lock(functionsLock_);
        for (auto iter = functions_.begin(); iter != functions_.end(); ++iter) {
            napi_release_threadsafe_function(iter->second, napi_tsfn_abort);
        }
        functions_.clear();
    };
    void SetResultInfo(string key, ResultInfo *resultInfo) {
        unique_lock<mutex> lock(resultsLock_);
        // 如果key已经存在，则覆盖对应的value
        results_[key] = resultInfo;
//        results_.emplace(key, resultInfo);
    }
    ResultInfo *GetResultInfo(string key) {
        unique_lock<mutex> lock(resultsLock_);
        auto iter = results_.find(key);
        if (iter == results_.end()) {
            return nullptr;
        }
        return iter->second;
    }

private:
    inline void SetThreadSafeFuntion(string name, napi_threadsafe_function fn) { functions_.emplace(name, fn); }
    unordered_map<string, napi_threadsafe_function> functions_;
    mutex functionsLock_;
    unordered_map<string, ResultInfo *> results_;
    mutex resultsLock_;
};
} 

#endif //MyNapi_threadsafe_manager_H
